//
//  STDBaseLayer.hpp
//  STDRenderSDK
//
//  Created by 陈学明 on 2023/3/15.
//

#ifndef STDBaseLayer_hpp
#define STDBaseLayer_hpp
#include <stdio.h>
#include <Manager/STDSGLContext.hpp>
#include <glm/glm.hpp>
#include <Effects/STDSBlendType.h>
#include <Effects/STDSBaseEffect.hpp>
#include <Basic/graphic/STDSRenderTarget.hpp>
#include <Effects/STDSDefaultEffect.hpp>
#include <Effects/STDSTransformationEffect.hpp>
#include <Effects/STDSHotShaderEffect.hpp>
#include <Effects/STDSGraphicEffect.h>
#include <Effects/STDSMaskKeyEffect.h>
#include <Basic/graphic/STDSObject.h>

enum STDLayerType {
    STDLayerTypeImage = 1, // 图片图层
    STDLayerTypeVideo, // 视频图层
    STDLayerTypeText, // 文本层
    STDLayerTypeShapen, // 形状图层
    STDLayerTypeEmpty, // 空图层
    STDLayerTypeCompose, // 预合成层
    STDLayerTypeSolidColor, // 纯色层
    STDLayerTypeCamora, // 摄像机层
};

using namespace glm;

/// 图层基类
class STDBaseLayer: public STDSObject {
public:
    STDBaseLayer() {
        
    }
    virtual ~STDBaseLayer(){
//        printf("dealloc--STDBaseLayer\n");
    }
public:
    
    virtual void initGL() {
        mTransformEffect = make_shared<STDSTransformationEffect>();
        mTransformEffect->setContext(mContext);
    }
    
    virtual void unInitGL() {
        mTransformEffect->unInitGL();
        for (auto effect: effects) {
            effect->unInitGL();
        }
    }
    
    
    void draw(shared_ptr<STDSTexture> tex) {
        auto keyEffect = getKeyEffect();
        shared_ptr<STDSRenderTarget> inputFbo = make_shared<STDSRenderTarget>(tex->getWidth(), tex->getHeight());
        inputFbo->bindSelf();
        keyEffect->setTexture(tex);
        keyEffect->setMaskTexture(mMaskTexture);
        keyEffect->draw();
        inputFbo->restore();
        mBodyTexture = inputFbo->getTexture();
    }
    
    virtual void draw() {
        if (mMaskTexture != nullptr && mBodyTexture == nullptr) {
            maskKey(mTexture);
        }
        shared_ptr<STDSRenderTarget> inputFbo = nullptr;

        for (auto effect: effects) {
            if (effect->isVisible() == false) {
                continue;
            }
            auto fbo = make_shared<STDSRenderTarget>(mSizeSRC.x, mSizeSRC.y);
            effect->mSizeSRC = mSizeSRC;
            fbo->bindSelf();
            if (inputFbo == nullptr) {
                effect->setTexture(mTexture);
            } else {
                effect->setTexture(inputFbo->getTexture());
            }
            effect->setBodyTexture(mBodyTexture);
            effect->draw();
            fbo->restore();
            inputFbo = fbo;
        }
        
        if (inputFbo == nullptr) {
            drawTexture(mTexture);
        } else {
            drawTexture(inputFbo->getTexture());
        }
    }
    
    virtual void maskKey(shared_ptr<STDSTexture> tex) {
        auto keyEffect = getKeyEffect();
        shared_ptr<STDSRenderTarget> inputFbo = make_shared<STDSRenderTarget>(tex->getWidth(), tex->getHeight());
        inputFbo->bindSelf();
        keyEffect->setTexture(tex);
        keyEffect->setMaskTexture(mMaskTexture);
        keyEffect->draw();
        inputFbo->restore();
        mBodyTexture = inputFbo->getTexture();
    }
    
    virtual void drawTexture(shared_ptr<STDSTexture> tex) {
        mTransformEffect->mSizeSRC = mSizeSRC;
        auto matV = mMatV*mTransformMat;
        mTransformEffect->setMatV(matV);
        mTransformEffect->setAlpha(mAlpha);
        mTransformEffect->setTexture(tex);
        mTransformEffect->draw();
    }
    
    virtual shared_ptr<STDSMaskKeyEffect> getKeyEffect() {
        if (mKeyEffect == nullptr) {
            mKeyEffect = make_shared<STDSMaskKeyEffect>();
            mKeyEffect->setContext(mContext);
        }
        return mKeyEffect;
    }
protected:
    void setType(STDLayerType type) {
        mType = type;
    }
    
public:
    void setBlend(STDSBlendType type) {
        mBlend = type;
    }
    
    STDSBlendType getBlend() {
        return mBlend;
    }
    
    STDLayerType getType() {
        return mType;
    }
    
    vec2 getLife() {
        return mLife;
    }
    
    void setLife(vec2 life) {
        mLife = life;
    }
    
    void setAlpha(float alpha) {
        mAlpha = alpha;
    }
    
    float getAlpha() {
        return mAlpha;
    }
    
    shared_ptr<STDSTexture> getTexture() {
        return mTexture;
    }
    
    virtual void setPrograss(float prograss) {
        mCurPrograss = prograss;
        mTransformEffect->setPrograss(prograss);
        for (auto effect: effects) {
            effect->setPrograss(prograss);
        }
    }
    
    virtual float getPrograss() {
        return mCurPrograss;
    }
    
    bool isVisible() {
        return mIsVisible;
    }
    
    void setVisible(bool visible) {
        mIsVisible = visible;
    }
    
    void setContext(shared_ptr<STDSGLContext> ctx) {
        mContext = ctx;
        initGL();
        for (auto e: effects) {
            e->setContext(ctx);
        }
    }
    
    shared_ptr<STDSGLContext> getContext() {
        return mContext;
    }
    
    int getId() {
        return mLayerId;
    }
    
    void setId(int ID) {
        mLayerId = ID;
    }
    
    void setSizeSRC(glm::vec2 size) {
        mSizeSRC = size;
        mAutoW = false;
        mAutoH = false;
        updataTransMat();
        for (auto &effect: effects) {
            effect->mSizeSRC = mSizeSRC;
        }
    }
    
    void setCenter(glm::vec2 point) {
        mCenter = point;
        updataTransMat();
    }
    
    void setScale(glm::vec2 scale) {
        mScale = scale;
        updataTransMat();
    }
    
    void setRotate(float angle) {
        mAngle = angle;
        updataTransMat();
    }
    
    void setAutoSize(bool autoW, bool autoH) {
        mAutoW = autoW;
        mAutoH = autoH;
        updataTransMat();
    }
    
    void setSizeCVS(glm::vec2 size) {
        mSizeCVS = size;
        updataTransMat();
    }
    
    void updataTransMat();
    
    void transformationTranslation(float dx, float dy);
    
    void transformationScale(float dx, float dy);
    
    void transformationRotation(float dAngle);
    
    void calculateAutoSize();
public:
    virtual void addEffect(int effect);
    
    virtual void changeEffectFloatValue(int effect, const char *paramName, float *floatValue, int n);
    
    virtual void changeEffectIntValue(int effect, const char *paramName, int *intValue, int n);
    
    virtual void changeEffectStringValue(int effect, const char *paramName, const char *stringValue);
    
    virtual void changeEffectBitmap(int effect, const char *paramName, const char *data, int width, int height);
    
    virtual void changeEffectTex(int effect, const char *paramName, unsigned int texId, int width, int height);
    
    virtual void removeEffect(int effect);
    
    virtual void visibleEffect(int effect, int visible);
    
    virtual bool checkEffectStatus(int effectType, const char *label);
    
    virtual void addHotEffect(const char *effectName, const char *effectRoot);
    
    virtual void removeHotEffect(const char *effectName);
    
    virtual void changeHotEffectFloatValue(const char *effectName, const char *paramName, float *floatValue, int n);
    
    virtual void changeHotEffectIntValue(const char *effectName, const char *paramName, int *intValue, int n);
    
    virtual void changeHotEffectStringValue(const char *effectName, const char *paramName, const char *stringValue);
    
    virtual void visibleHotEffect(const char *effectName, int isVisible);
    
    virtual void clearEffects();
    
    virtual void addHotFilter(const char *filter, const char *effectRoot);
    
    virtual void removeHotFilter(const char *filter);
    
    virtual void visibleHotFilter(const char *filter, int isVisible);
    
    virtual void changeHotFilterFloatValue(const char *filter, const char *effectName, const char *paramName, float *floatValue, int n);
    
    virtual void changeHotFilterIntValue(const char *filter, const char *effectName, const char *paramName, int *intValue, int n);
    
    virtual void changeHotFilterStringValue(const char *filter, const char *effectName, const char *paramName, const char *stringValue);
    
public:
    virtual void replaceImageAsset(int assetId, const char *path);
    
    virtual void replaceImageTex(int assetId, const unsigned int textureId, float width, float height);
    
    virtual void replaceImageData(int assetId, const unsigned char *data, float width, float height);
    
    virtual void replaceMaskAsset(int assetId, const char *path);
    
    virtual void replaceMaskTex(int assetId, const unsigned int textureId, float width, float height);
    
    virtual void replaceMaskData(int assetId, const unsigned char *data, float width, float height);
    
public:
    vector<shared_ptr<STDSBaseEffect>> effects;
    int mLayerId{0}; // 图层ID
    shared_ptr<STDSGLContext> mContext{nullptr}; // 上下文
    shared_ptr<STDSTransformationEffect> mTransformEffect{nullptr};// 仿射变换
    bool mIsVisible{true}; // 是否可见
    STDSBlendType mBlend{STDSBlendTypeNormal}; // 混合模式
    STDLayerType mType; // 图层类型
    vec2 mLife{0.0, 0.0}; // 生命，x 开始，y 结束
    float mCurPrograss{0.0}; // 进度
    float mAlpha{1.0}; // 透明度
    shared_ptr<STDSTexture> mTexture{nullptr};
    shared_ptr<STDSTexture> mBodyTexture{nullptr};
    shared_ptr<STDSTexture> mMaskTexture{nullptr};
    glm::vec2 mSizeSRC{0, 0}; // 图层大小
    glm::vec2 mSizeCVS{0, 0}; // 画布大小
    glm::vec2 mCenter{0, 0}; // 中心点
    glm::vec2 mScale{1.0, 1.0}; // 缩放
    float mAngle{0.0};// 旋转角度
    glm::mat4 mMatV{1.0}; // 顶点变换
    glm::mat4 mTransformMat{1.0}; // 仿射变换矩阵
    bool mAutoW{true};// 自动宽度
    bool mAutoH{true};// 自动高度
    glm::vec2 mAutoSize{0.0, 0.0}; // 自动大小
    shared_ptr<STDSMaskKeyEffect> mKeyEffect{nullptr};
};
#endif /* STDBaseLayer_hpp */
